﻿using ACC.Business;
using ACC.Data;
using ACC.Data.ACCLog;
using ACC.Data.Comm;
using ACC.Data.Entities.Common;
using ACC.Data.Line;
using ACC.Device;
using ACC.Device.Common;
using ACC.Interface.Implement;
using ACC.Interface.Extensions;
using ACC.Util.Common;
using ACC.Util.DB;
using ACC.Util.Log;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
using ACC.Business.Process;
using ACC.Device.Client;
using System.Reflection;

namespace ACC.Interface
{
    public class ProcessClient : ICommandProcess
    {
        protected Regex INT_PATTERN = new Regex("INT\\[(\\d+)\\]", RegexOptions.IgnoreCase);
        protected Regex REAL_PATTERN = new Regex("REAL\\[(\\d+)\\]", RegexOptions.IgnoreCase);
        protected Regex BOOL_PATTERN = new Regex("BOOL\\[(\\d+)\\]", RegexOptions.IgnoreCase);
        protected Regex STRING_PATTERN = new Regex("STRING\\[(\\d+)\\]", RegexOptions.IgnoreCase);

        const string LOG_NAME = "Client";
        public static Log logger;

        public ProcessClient()
        {
            LogFactory.StartLog(LOG_NAME, "\\" + LOG_NAME + ".Log");
            logger = LogFactory.GetLog(LOG_NAME, typeof(ProcessClient).ToString());
        }

        public virtual bool ExecuteCommand(string userID, string cmdType, string cmdName, XmlDocument xmlDoc, out string msg, out XmlDocument xmlRet)
        {
            bool bRet = true;
            msg = string.Empty;
            xmlRet = null;
            string retData = string.Empty;

            #region ACC原有请求的参数解析
            XmlNodeList xmlparams = xmlDoc.SelectNodes("root/params/param");
            Hashtable param = new Hashtable();
            DictionaryEx<string, object> parameters = new DictionaryEx<string, object>();
            for (int i = 0; i < xmlparams.Count; i++)
            {
                string paramname = xmlparams[i].Attributes["name"].Value.ToLower();
                string paramtype = xmlparams[i].Attributes["datatype"].Value;
                string paramvalue = xmlparams[i].Attributes["value"].Value;

                if (!param.ContainsKey(paramname))
                {
                    param[paramname] = paramvalue;
                    parameters[paramname] = paramvalue;
                }
            }
            #endregion

            #region 解析XML获取请求对象Request
            ClientRequest clientRequest = null;
            XmlNode xmldtlist = xmlDoc.SelectSingleNode("root/data");
            if (xmldtlist != null && xmldtlist.FirstChild != null)
            {
                string data = JsonHelper.DecompressString(xmldtlist.FirstChild.InnerText);
                logger.Debug(data);
                clientRequest = JsonHelper.ToObject<ClientRequest>(data);
            }

            if (clientRequest == null)
            {
                msg = "Invalid request";

                return false;
            }

            #endregion

            #region 分析请求参数并验证
            ClientResponse clientResponse = new ClientResponse();
            clientResponse.CmdName = clientRequest.CmdName;
            clientResponse.Result = true;
            clientResponse.Message = string.Empty;
            clientResponse.Data = string.Empty;

            String lineName = clientRequest.Parameters.ContainsKey("Line") ? clientRequest.Parameters["Line"].ToString() : "";
            String op = clientRequest.Parameters.ContainsKey("OP") ? clientRequest.Parameters["OP"].ToString() : "";
            String station = clientRequest.Parameters.ContainsKey("STN") ? clientRequest.Parameters["STN"].ToString() : "";

            StnRunningData stnData = null;
            LineData lineData = null;

            if (clientRequest.CmdName.ToLower() != "bin")
            {
                lineData = LineManager.GetLineData(lineName);
                if (lineData == null)
                {
                    clientResponse.Result = false;
                    clientResponse.Message = msg = "Line " + lineName + " not exists or not started ";
                }
                else
                {
                    if (!lineData.Cfg.OPCfg.ContainsKey(op) || !lineData.Cfg.StnCfg.ContainsKey(station))
                    {
                        clientResponse.Result = false;
                        clientResponse.Message = msg = "OP " + op + " not exists or station " + station + " not exists ";
                    }
                    else
                    {
                        OPCfg opCfg = lineData.Cfg.OPCfg[op];
                        StnCfg stnCfg = lineData.Cfg.StnCfg[station];
                        stnData = stnCfg == null ? null : lineData.RunningData.StnDatas[stnCfg];
                        if (stnData == null)
                        {
                            clientResponse.Result = false;
                            clientResponse.Message = msg = "Station " + station + " not started or not exists ";
                        }
                    }
                }
            }

            if (!clientResponse.Result)
            {
                bRet = false;
                retData = JsonHelper.CompressString(JsonHelper.ToJson<ClientResponse>(clientResponse));
                return false;
            }

            uint partTypeId;
            uint.TryParse(clientRequest.Parameters.ContainsKey("PartTypeId") ? clientRequest.Parameters["PartTypeId"].ToString() : "0", out partTypeId);
            partTypeId = partTypeId == 0 ? ((stnData == null || stnData.PartNo == null) ? 0 : stnData.PartNo.BomCfg.PartTypeID) : partTypeId;
            String operatorId = clientRequest.Parameters.ContainsKey("OperatorId") ? clientRequest.Parameters["OperatorId"].ToString() : "";
            String operatorPwd = clientRequest.Parameters.ContainsKey("OperatorPwd") ? clientRequest.Parameters["OperatorPwd"].ToString() : "";
            String[] barcodes = clientRequest.Parameters.ContainsKey("Barcodes") ? JsonHelper.ToObject<String[]>(clientRequest.Parameters["Barcodes"].ToString()) : null;
            String oprckType = clientRequest.Parameters.ContainsKey("Type") ? clientRequest.Parameters["Type"].ToString() : "";
            string bomItems = clientRequest.Parameters.ContainsKey("BOMItems") ? clientRequest.Parameters["BOMItems"].ToString() : "";
            string idName = clientRequest.Parameters.ContainsKey("IDName") ? clientRequest.Parameters["IDName"].ToString() : "";
            #endregion

            #region 处理不同类型请求命令
            switch (clientRequest.CmdName.ToLower())
            {
                case "parttypelist":
                    {
                        lock (stnData)
                        {
                            msg = DoGetPartTypeList(stnData, ref clientResponse);
                        }
                    }
                    break;
                case "changemodel":
                    {
                        lock (stnData)
                        {
                            msg = DoModelChange(stnData, partTypeId, ref clientResponse);
                        }
                    }
                    break;
                case "getmodel":
                    {
                        msg = DoGetModel(stnData, partTypeId, ref clientResponse);
                    }
                    break;
                case "getmodelbybarcode":
                    {
                        msg = DoGetModelByBarcode(stnData, barcodes, ref clientResponse);
                    }
                    break;
                case "operatorstationlist":
                    {
                        msg = DoGetStationList(stnData, operatorId, ref clientResponse);
                    }
                    break;
                case "operatorlogin":
                    {
                        msg = DoOperatorLogin(stnData, operatorId, ref clientResponse);
                    }
                    break;
                case "operatorlogout":
                    {
                        msg = DoOperatorLogout(stnData, operatorId, ref clientResponse);
                    }
                    break;
                case "operatorcheck":
                    {
                        msg = DoOperatorCheck(stnData, operatorId, oprckType, ref clientResponse);
                    }
                    break;
                case "usercheck":
                    {
                        msg = DoUserCheck(stnData, operatorId, operatorPwd, ref clientResponse);
                    }
                    break;
                case "nextstep":
                    lock (stnData)
                    {
                        msg = DoNextStep(stnData, partTypeId, barcodes, ref clientResponse);
                    }
                    break;
                case "preload":
                    {
                        lock (stnData)
                        {
                            msg = DoPreLoad(stnData, partTypeId, barcodes, idName, ref clientResponse);
                        }
                    }
                    break;
                case "load":
                    {
                        lock (stnData)
                        {
                            List<ClientProcData> lstProcDatas = (clientRequest.Parameters.ContainsKey("ProcDatas") && clientRequest.Parameters["ProcDatas"] != null) ? JsonHelper.ToObject<List<ClientProcData>>(clientRequest.Parameters["ProcDatas"].ToString()) : null;
                            ACCDevice.UnloadParam unloadParam = null;
                            BomCfg bomCfg = lineData.Cfg.BomCfgByID[partTypeId];
                            if (null != bomCfg && lstProcDatas != null)
                            {
                                unloadParam = new ACCDevice.UnloadParam();
                                GetUnloadRealCfg(stnData, lstProcDatas, bomCfg, ref unloadParam);
                            }
                            if (unloadParam == null)
                            {
                                stnData.Variables.Remove("N_REAL");
                                stnData.Variables.Remove("N_STRING");
                            }
                            else
                            {
                                stnData.Variables["N_REAL"] = unloadParam.N_Real;
                                stnData.Variables["N_STRING"] = unloadParam.N_String;
                            }

                            msg = DoLoad(stnData, partTypeId, barcodes, ref clientResponse);
                        }
                    }
                    break;
                case "unload":
                    {
                        lock (stnData)
                        {
                            foreach (string varKey in clientRequest.Variables.Keys.ToArray())
                            {
                                if (!string.IsNullOrEmpty(varKey) && clientRequest.Variables.ContainsKey(varKey))
                                {
                                    stnData.Variables[varKey] = clientRequest.Variables[varKey];
                                }
                            }

                            int statusBits = int.Parse((clientRequest.Parameters.ContainsKey("StatusBits") && clientRequest.Parameters["StatusBits"] != null) ? clientRequest.Parameters["StatusBits"].ToString() : "0");
                            int failureBits = int.Parse((clientRequest.Parameters.ContainsKey("FailureBits") && clientRequest.Parameters["FailureBits"] != null) ? clientRequest.Parameters["FailureBits"].ToString() : "0");

                            List<ClientProcData> lstProcDatas = (clientRequest.Parameters.ContainsKey("ProcDatas") && clientRequest.Parameters["ProcDatas"] != null) ? JsonHelper.ToObject<List<ClientProcData>>(clientRequest.Parameters["ProcDatas"].ToString()) : null;
                            msg = DoUnload(stnData, partTypeId, barcodes, statusBits,failureBits,lstProcDatas, ref clientResponse);
                        }
                    }
                    break;
                case "print":
                    {
                        lock (stnData)
                        {
                            foreach (string varKey in clientRequest.Variables.Keys.ToArray())
                            {
                                if (!string.IsNullOrEmpty(varKey) && clientRequest.Variables.ContainsKey(varKey))
                                {
                                    stnData.Variables[varKey] = clientRequest.Variables[varKey];
                                }
                            }

                            msg = DoPrint(stnData, ref clientResponse);
                        }
                    }
                    break;
                case "bin":
                    {
                        List<ClientLotTrackItem> lstLotItems = (clientRequest.Parameters.ContainsKey("Materials") && clientRequest.Parameters["Materials"] != null) ? JsonHelper.ToObject<List<ClientLotTrackItem>>(clientRequest.Parameters["Materials"].ToString()) : null;

                        msg = DoBin(clientRequest, lstLotItems, ref clientResponse);
                    }
                    break;
                case "lot":
                    {
                        lock (stnData)
                        {
                            msg = DoLot(stnData, clientRequest, ref clientResponse);
                        }
                    }
                    break;
                case "binlot":
                    {
                        lock (stnData)
                        {
                            msg = DoBinLot(stnData, clientRequest, ref clientResponse);
                        }
                    }
                    break;
                #region 整合打卡功能
                case "login":
                    {
                        msg = DoLogin(lineData, operatorId, ref clientResponse);
                    }
                    break;
                case "logout":
                    {
                        msg = DoLogout(lineData, operatorId, ref clientResponse);
                    }
                    break;
                case "logoutall":
                    {
                        msg = DoLogoutAll(lineData, operatorId, ref clientResponse);
                    }
                    break;
                case "getworkorder":
                    {
                        DateTime woDate;
                        String sDate = clientRequest.Parameters.ContainsKey("Date") ? clientRequest.Parameters["Date"].ToString() : DateTime.Now.ToString("yyyy-mm-dd");
                        DateTime.TryParse(sDate, out woDate);
                        msg = DoGetWorkOrder(lineData, operatorId, woDate, ref clientResponse);
                    }
                    break;
                case "saveworkorder":
                    {
                        DateTime woDate;
                        String sDate = clientRequest.Parameters.ContainsKey("Date") ? clientRequest.Parameters["Date"].ToString() : DateTime.Now.ToString("yyyy-mm-dd");
                        DateTime.TryParse(sDate, out woDate);
                        List<ClientWorkOrder> lstWorkOrder = (clientRequest.Parameters.ContainsKey("WorkOrder") && clientRequest.Parameters["WorkOrder"] != null) ? JsonHelper.ToObject<List<ClientWorkOrder>>(clientRequest.Parameters["WorkOrder"].ToString()) : null;
                        msg = DoSaveWorkOrder(lineData, operatorId, woDate, lstWorkOrder, ref clientResponse);
                    }
                    break;
                case "updateworkorderqty":
                    {

                        DateTime woDate;
                        String sDate = clientRequest.Parameters.ContainsKey("Date") ? clientRequest.Parameters["Date"].ToString() : DateTime.Now.ToString("yyyy-mm-dd");
                        DateTime.TryParse(sDate, out woDate);
                        int qty;
                        String sQty = clientRequest.Parameters.ContainsKey("Quantity") ? clientRequest.Parameters["Quantity"].ToString() : "1";
                        int.TryParse(sQty, out qty);
                        if (qty < 1)
                            qty = 1;
                        msg = DoUpdateWorkOrderQuantity(lineData, partTypeId, qty, ref clientResponse);
                    }
                    break;
                case "getshiftcode":
                    {
                        int shiftcode = lineData.RunningData.GetCurrentShift().ShiftOrder;
                        clientResponse.Data = shiftcode;
                        msg = string.Empty;
                    }
                    break;
                case "getstationoperator":
                    {
                        clientResponse.Data = GetOperator(stnData, stnData.Operator);
                        msg = string.Empty;
                    }
                    break;
                case "getdatetime":
                    {
                        clientResponse.Data = DateTime.Now;
                        msg = string.Empty;
                    }
                    break;
                #endregion
                case "materialin":
                    StnProcess stnProcess = LineManager.Lines[lineData.Line].StnProcesses[stnData.StnCfg];
                    lock (stnData)
                    {
                        foreach (string varKey in clientRequest.Variables.Keys.ToArray())
                        {
                            if (!string.IsNullOrEmpty(varKey) && clientRequest.Variables.ContainsKey(varKey))
                            {
                                stnData.Variables[varKey] = clientRequest.Variables[varKey];
                            }
                        }

                        stnProcess.OnCommonEvent(stnProcess.Device, PLCEventType.UserDefined1, true);
                    }
                    break;
                case "materialout":
                    StnProcess stnProcess1 = LineManager.Lines[lineData.Line].StnProcesses[stnData.StnCfg];
                    lock (stnData)
                    {
                        foreach (string varKey in clientRequest.Variables.Keys.ToArray())
                        {
                            if (!string.IsNullOrEmpty(varKey) && clientRequest.Variables.ContainsKey(varKey))
                            {
                                stnData.Variables[varKey] = clientRequest.Variables[varKey];
                            }
                        }

                        stnProcess1.OnCommonEvent(stnProcess1.Device, PLCEventType.UserDefined2, true);
                    }
                    break;
                default:
                    return XmlCommand.commandList["unknown"].ExecuteCommand(userID, cmdType, cmdName, xmlDoc, out msg, out xmlRet);
            }
            #endregion

            #region 返回处理结果Response
            logger.Debug(JsonHelper.ToJson<ClientResponse>(clientResponse));
            retData = JsonHelper.CompressString(JsonHelper.ToJson<ClientResponse>(clientResponse));
            xmlRet = CreateResponseXML(cmdType, cmdName, bRet, msg, retData);
            #endregion

            return bRet;
        }

        #region 获取型号列表
        protected virtual string DoGetPartTypeList(StnRunningData stnData, ref ClientResponse clientResponse)
        {
            List<BomCfg> lstBomCfg = stnData.StnCfg.LineCfg.LineData.Cfg.BomCfg.Values.OrderBy(c => c.Sequence).ToList();
            List<ClientPartType> lstPartTypeDesc = new List<ClientPartType>();
            foreach (BomCfg bom in lstBomCfg)
            {
                lstPartTypeDesc.Add(new ClientPartType()
                {
                    PartTypeId = (int)bom.PartTypeID,
                    PartNo = bom.PartNo,
                    Description = bom.DescLocal,
                    Sequence = bom.Sequence.HasValue ? (int)bom.Sequence : 0
                });
            }

            StnEventLog.Log(stnData, StnLog.LogType.Event, DataManager.MessageResource[Constants.MONITOR_PARTTYPEDESC_DOWNLOAD]);

            clientResponse.Data = lstPartTypeDesc;

            return string.Empty;
        }
        #endregion

        #region 换型处理 / 获取型号(PartNo) BOM, ProcessData, Limits, StatusBit
        protected virtual bool StnCheckModel(StnRunningData stnData, uint partTypeId, out string msg)
        {
            msg = string.Empty;

            if (stnData == null || stnData.StnCfg.LineCfg.LineData == null || partTypeId <= 0)
            {
                return false;
            }

            LineData lineData = stnData.StnCfg.LineCfg.LineData;
            BomCfg bomCfg = lineData.Cfg.BomCfgByID[partTypeId];

            if (null == bomCfg)
            {
                msg = string.Format("PartTypeId {0} 不存在", partTypeId);
            }
            else
            {
                RuningPartNo pt = lineData.RunningData.RunningPartNos[bomCfg.PartNo];
                if (pt == null)
                {
                    msg = string.Format("PartNo {0} 不存在或者没有启动", bomCfg.PartNo);
                }
            }

            if (!string.IsNullOrEmpty(msg))
            {
                logger.Error(msg);
                return false;
            }

            return true;
        }

        protected virtual bool StnModelChange(StnRunningData stnData, uint partTypeId, out string msg)
        {
            msg = string.Empty;

            if (stnData == null || stnData.StnCfg.LineCfg.LineData == null)
            {
                return false;
            }

            LineData lineData = stnData.StnCfg.LineCfg.LineData;
            StnProcess stnProcess = LineManager.Lines[lineData.Line].StnProcesses[stnData.StnCfg];
            RuningPartNo pt = lineData.RunningData.RunningPartNos[lineData.Cfg.BomCfgByID[partTypeId].PartNo];

            (stnProcess.Device as ClientCommonDevice).LastPartTypeId = pt.BomCfg.PartTypeID;
            stnProcess.OnModelChange(stnProcess.Device);
            ACCDevice.PartTypeDataResult partTypeDataResult = (stnProcess.Device as ClientCommonDevice).LastPartTypeDataResult;
            if (partTypeDataResult == null || partTypeDataResult.ErrorCode != ACCCode.ACCOK)
            {
                msg = partTypeDataResult == null ? "换型处理失败" : partTypeDataResult.ErrorMessage;
            }

            if (!string.IsNullOrEmpty(msg))
            {
                logger.Error(msg);
                return false;
            }

            EventLog.LogServerEvent(stnData, ErrorConstants.EVENT_MODELCHANGE, pt.BomCfg.PartNo, pt.BomCfg.Desc);

            if (stnData.IsFirstStn) // 首站才会发送换型变化提醒给其它关联站
            {
                ACCDevice.PartTypeDataResult modelChgResult = new ACCDevice.PartTypeDataResult();
                modelChgResult.PartNo = pt;
                modelChgResult.ErrorCode = ACCCode.ACCOK;
                modelChgResult.ErrorMessage = string.Empty;
                modelChgResult.ReturnCode = Convert.ToInt32(ACCCode.ACCOK);

                if (ACCCode.ACCOK != stnProcess.SendModelChangeRequest(stnProcess.Device, modelChgResult))
                {
                    logger.Error("Model change, send model change request failed");
                }
            }

            return true;
        }

        protected virtual ClientModelChangeResult StnModelParameters(StnRunningData stnData, uint partTypeId)
        {
            List<ClientProcData> lstProcData = new List<ClientProcData>();
            List<ClientBomItems> lstBoms = new List<ClientBomItems>();
            List<ClientParttypeData> lstPartdata = new List<ClientParttypeData>();
            //List<ClientFailureBit> lstFailureBits = new List<ClientFailureBit>();
            List<ClientFailureWord> lstFailureBits = new List<ClientFailureWord>();
            List<ClientParttypeTagCfg> lstPartTypeTag = new List<ClientParttypeTagCfg>();
            List<ClientLotTrackItem> lstLotItem = new List<ClientLotTrackItem>();

            LineData lineData = stnData == null ? null : stnData.StnCfg.LineCfg.LineData;
            BomCfg bomCfg = lineData == null ? null : lineData.Cfg.BomCfgByID[partTypeId];
            RuningPartNo pt = bomCfg == null ? null : lineData.RunningData.RunningPartNos[bomCfg.PartNo];
            StnProcess stnProcess = lineData == null ? null : LineManager.Lines[lineData.Line].StnProcesses[stnData.StnCfg];

            if (stnData == null || stnData.StnCfg.LineCfg.LineData == null || bomCfg == null || pt == null || stnProcess == null)
            {
                return new ClientModelChangeResult()
                {
                    PartType = null,
                    ProcDatas = lstProcData,
                    BOMItems = lstBoms,
                    StatusBits = lstFailureBits,
                    PartTypeTag = lstPartTypeTag,
                    PartTypeDatas = lstPartdata
                };
            }

            ClientPartType partType = new ClientPartType()
            {
                PartTypeId = (int)bomCfg.PartTypeID,
                Description = bomCfg.Desc,
                PartNo = bomCfg.PartNo,
                Sequence = bomCfg.Sequence != null ? (int)bomCfg.Sequence : 0
            };

            lstBoms = stnProcess.GetBomItemCfg();

            lstProcData = stnProcess.GetProcessDataCfg(bomCfg, 0);

            lstPartdata = stnProcess.GetPartTypeData(bomCfg.PartNo);

            lstFailureBits = stnProcess.GetFailureWordCfg(bomCfg);

            lstPartTypeTag = stnProcess.GetPartTypeTagCfg(bomCfg);

            // 获取当前工位物料信息
            lstLotItem = stnProcess.GetComponentSet(false);

            return new ClientModelChangeResult()
            {
                PartType = partType,
                ProcDatas = lstProcData,
                BOMItems = lstBoms,
                StatusBits = lstFailureBits,
                PartTypeTag = lstPartTypeTag,
                PartTypeDatas = lstPartdata,
                ComponentSet = lstLotItem
            };
        }

        protected virtual string DoModelChange(StnRunningData stnData, uint partTypeId, ref ClientResponse clientResponse)
        {
            string msg = string.Empty;

            if (!StnCheckModel(stnData, partTypeId, out msg))
            {
                clientResponse.Result = false;
                return clientResponse.Message = msg;
            }

            if (!StnModelChange(stnData, partTypeId, out msg))
            {
                clientResponse.Result = false;
                return clientResponse.Message = msg;
            }

            clientResponse.Data = StnModelParameters(stnData, partTypeId);

            return msg;
        }

        protected virtual string DoGetModel(StnRunningData stnData, uint partTypeId, ref ClientResponse clientResponse)
        {
            string msg = string.Empty;

            if (partTypeId <= 0)
            {
                partTypeId = stnData.PartNo == null ? 0 : stnData.PartNo.BomCfg.PartTypeID;
            }

            if (!StnCheckModel(stnData, partTypeId, out msg))
            {
                clientResponse.Result = false;
                return clientResponse.Message = msg;
            }

            clientResponse.Data = StnModelParameters(stnData, partTypeId);

            return msg;
        }

        protected virtual string DoGetModelByBarcode(StnRunningData stnData, String[] barcodes, ref ClientResponse clientResponse)
        {
            List<ClientPartType> lstPartTypeDesc = new List<ClientPartType>();
            LineData lineData = stnData.StnCfg.LineCfg.LineData;
            StnProcess stnProcess = LineManager.Lines[lineData.Line].StnProcesses[stnData.StnCfg];
            foreach (string barcode in barcodes)
            {
                lstPartTypeDesc.Add(stnProcess.OnGetModelByBarcode(barcode));
            }

            clientResponse.Data = lstPartTypeDesc;
            clientResponse.Result = (lstPartTypeDesc.Count > 0 && lstPartTypeDesc[0] != null) ? true : false;

            return string.Empty;
        }
        #endregion

        #region 工位登入/登出 权限检查处理 / 线长获取所属线工位列表（包含每个工位有权限操作工信息）
        protected virtual string DoGetStationList(StnRunningData stnData, string operatorId, ref ClientResponse clientResponse)
        {
            string msg = string.Empty;

            LineData lineData = stnData.StnCfg.LineCfg.LineData;
            // 获取该LineName下的Stn列表和Operator列表
            List<ClientStnCfg> clientStnCfgs = new List<ClientStnCfg>();
            foreach (StnCfg stn in lineData.Cfg.StnCfg.Values.ToArray())
            {
                StnProcess stnProcess = LineManager.Lines[lineData.Line].StnProcesses[stn];

                // 过滤掉不同支线的站
                if (stnData != null &&
                    lineData.RunningData.StnDatas.ContainsKey(stn) &&
                    !stnProcess.IsSameSegment(lineData.RunningData.StnDatas[stn].Route, stnData.Route))
                    continue;

                List<ClientOperator> clientOperators = new List<ClientOperator>();

                DataTable dt = DataManager.DBHelper.Query("SELECT * FROM ACC_OPERATOR WHERE LINE='" + lineData.Line + "' AND ENABLE = '1' AND OP like '%" + stn.OPCfg.OP + "%' ");
                if (dt != null && dt.Rows.Count > 0)
                {
                    foreach (DataRow row in dt.Rows)
                    {
                        clientOperators.Add(new ClientOperator()
                        {
                            Name = row["Name"].ToString(),
                            OperatorId = row["OperatorId"].ToString()
                        });
                    }
                }

                clientStnCfgs.Add(new ClientStnCfg()
                {
                    Line = stn.LineCfg.Line,
                    OP = stn.OPCfg.OP,
                    STN = stn.Name,
                    Description = stn.Name,
                    Sequence = stn.OPCfg.Sequence,
                    Operators = clientOperators
                });
            }

            clientResponse.Data = clientStnCfgs;

            return msg;
        }

        protected virtual string DoOperatorLogin(StnRunningData stnData, string operatorId, ref ClientResponse clientResponse)
        {
            string msg = string.Empty;

            System.Data.DataTable dt = DataManager.DBHelper.Query(string.Format("SELECT * FROM ACC_OPERATOR WHERE LINE = '{0}' AND OPERATORID = '{1}' AND ENABLE = '1'", stnData.StnCfg.LineCfg.Line, operatorId));
            if (null != dt && dt.Rows.Count > 0)
            {
                string currentOperatorId = stnData.Operator;
                ClientOperator clientOperator = new ClientOperator()
                                            {
                                                OperatorId = operatorId,
                                                Name = dt.Rows[0]["NAME"].ToString(),
                                                LoginTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
                                            };
                LineData lineData = stnData.StnCfg.LineCfg.LineData;
                StnProcess stnProcess = LineManager.Lines[lineData.Line].StnProcesses[stnData.StnCfg];

                if (stnData.StnCfg.OprLogon && stnData.StnCfg.OprValidate) // 配置了Station要登录要验证Operator
                {
                    if (!(dt.Rows[0]["OP"] is DBNull))
                    {
                        List<string> vops = new List<string>(dt.Rows[0]["OP"].ToString().Split(Constants.SEPARATOR.ToCharArray()));

                        if (vops == null || !vops.Contains(stnData.StnCfg.OPCfg.OP))
                        {
                            clientResponse.Result = false;
                            clientResponse.Message = msg = string.Format("用户{0}没有工位{1}的权限", operatorId, stnData.StnCfg.OPCfg.OP);
                        }
                    }
                    else
                    {
                        clientResponse.Result = false;
                        clientResponse.Message = msg = string.Format("用户{0}没有工位{1}的权限", operatorId, stnData.StnCfg.OPCfg.OP);
                    }
                }

                if (clientResponse.Result)
                {
                    stnData.Operator = operatorId;
                    clientResponse.Data = clientOperator;
                    clientResponse.Message = msg = string.Format("用户{0}登录成功", operatorId);
                }

                // 通知客户端操作工发生了变化
                if (currentOperatorId != stnData.Operator)
                {
                    (stnProcess.Device as ClientCommonDevice).ClientLastOperatorId[stnData.StnCfg.Name] = operatorId;
                    (stnProcess.Device as ClientCommonDevice).ClientLastOperator[operatorId] = clientOperator;
                    stnProcess.OnLogin(stnProcess.Device);
                }
            }
            else
            {
                clientResponse.Result = false;
                clientResponse.Message = msg = string.Format("用户{0}不存在或被禁用", operatorId);
            }
            StnEventLog.Log(stnData, StnLog.LogType.Event, clientResponse.Message);

            return msg;
        }

        protected virtual string DoOperatorLogout(StnRunningData stnData, string operatorId, ref ClientResponse clientResponse)
        {
            string msg = string.Empty;
            ClientOperator clientOperator = null;

            if (!string.IsNullOrEmpty(operatorId))
            {
                System.Data.DataTable dt = DataManager.DBHelper.Query(string.Format("SELECT * FROM ACC_OPERATOR WHERE LINE = '{0}' AND  OPERATORID = '{1}' AND ENABLE = '1'", stnData.StnCfg.LineCfg.Line, operatorId));
                if (null != dt && dt.Rows.Count > 0)
                {
                    clientOperator = new ClientOperator()
                    {
                        OperatorId = operatorId,
                        Name = dt.Rows[0]["NAME"].ToString(),
                        LogoutTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
                    };
                }

                if (stnData.Operator != operatorId)
                {
                    clientResponse.Result = false;
                    clientResponse.Message = msg = string.Format("{0}不是当前登录的用户,不能登出", operatorId);
                }
            }

            if (clientResponse.Result)
            {
                LineData lineData = stnData.StnCfg.LineCfg.LineData;
                StnProcess stnProcess = LineManager.Lines[lineData.Line].StnProcesses[stnData.StnCfg];

                stnData.Operator = string.Empty;

                (stnProcess.Device as ClientCommonDevice).ClientLastOperatorId[stnData.StnCfg.Name] = operatorId;
                (stnProcess.Device as ClientCommonDevice).ClientLastOperator[operatorId] = clientOperator;
                stnProcess.OnLogout(stnProcess.Device);

                clientResponse.Data = clientOperator;
                clientResponse.Message = msg = string.Format("用户{0}登出成功", operatorId);
            }

            StnEventLog.Log(stnData, StnLog.LogType.Event, clientResponse.Message);

            return msg;
        }

        protected virtual string DoOperatorCheck(StnRunningData stnData, string operatorId, string oprckType, ref ClientResponse clientResponse)
        {
            string msg = string.Empty;

            // 验证用户OperatorID是否是线长
            switch (oprckType.ToLower())
            {
                case "operatorassign":
                case "setprocdata":
                    {
                        string sql = "SELECT DISTINCT PRIVID FROM ACC_PRIVILEGES_ROLE WHERE PRIVID = 990101 AND ROLEID IN (SELECT DISTINCT ROLEID FROM ACC_ROLE_USER WHERE USERID IN (SELECT USERID FROM ACC_USER WHERE OPERATORID = '" + operatorId + "'))";
                        DataTable dt = DataManager.DBHelper.Query(sql);
                        if (dt == null || dt.Rows.Count <= 0)
                        {
                            clientResponse.Result = false;
                            clientResponse.Message = msg = string.Format("用户{0}没有指定操作权限", operatorId);
                        }
                    }
                    break;
                default:
                    clientResponse.Result = false;
                    clientResponse.Message = msg = string.Format("命令类型{0}不支持", oprckType);
                    break;
            }

            return msg;
        }
        protected virtual string DoUserCheck(StnRunningData stnData, string userId, string userPwd, ref ClientResponse clientResponse)
        {
            string msg = string.Empty;
            clientResponse.Result = false;

            // 验证用户用户名和密码
            string sql = "SELECT * FROM ACC_USER WHERE USERNAME = '" + userId + "'";
            DataTable dt = DataManager.DBHelper.Query(sql);
            if (dt == null || dt.Rows.Count <= 0)
            {
                msg = string.Format("用户{0}不存在", userId);
            }
            else
            {
                string pwd = dt.Rows[0]["PASSWORD"].ToString();
                if (pwd != userPwd)
                {
                    msg = string.Format("用户{0}密码错误", userId);
                }
                else
                {
                    clientResponse.Result = true;
                }
            }
            clientResponse.Message = msg;

            return msg;
        }
        #endregion

        #region 整合打卡功能
        private ClientOperator GetOperator(StnRunningData stnData, string operatorId)
        {
            ClientOperator clientOperator = null;
            if (!string.IsNullOrEmpty(operatorId))
            {
                System.Data.DataTable dt = DataManager.DBHelper.Query(string.Format("SELECT * FROM ACC_OPERATOR WHERE LINE = '{0}' AND OPERATORID = '{1}' AND ENABLE = '1'",
                    stnData.StnCfg.LineCfg.Line, operatorId));
                if (null != dt && dt.Rows.Count > 0)
                {
                    clientOperator = new ClientOperator()
                    {
                        OperatorId = operatorId,
                        Name = dt.Rows[0]["NAME"].ToString()
                    };
                }
            }

            return clientOperator;
        }

        protected virtual string DoLogin(LineData lineData, string operatorId, ref ClientResponse clientResponse)
        {
            string msg = string.Empty;
            DateTime ctime = DateTime.Now;

            System.Data.DataTable dt = DataManager.DBHelper.Query(string.Format("SELECT * FROM ACC_OPERATOR WHERE LINE = '{0}' AND OPERATORID = '{1}' AND ENABLE = '1'",
                lineData.Line, operatorId));
            if (null != dt && dt.Rows.Count > 0)
            {
                List<ClientStnCfg> stations = new List<ClientStnCfg>();
                ClientOperator clientOperator = new ClientOperator()
                {
                    OperatorId = operatorId,
                    Name = dt.Rows[0]["NAME"].ToString(),
                    LoginTime = ctime.ToString("yyyy-MM-dd HH:mm:ss")
                };
                string ops = dt.Rows[0]["OP"].ToString();

                if (!string.IsNullOrEmpty(ops))
                {
                    string[] opArray = ops.Split(new char[] { ';' });
                    if (opArray != null && opArray.Length > 0)
                    {
                        // 检查站的最大登录数，如果超过，则登出最早登录用户（删除当前表记录，插入His（Type=2非正常退出）
                        // 插入登录信息（当前登录表和His表）
                        DbConnection conn = DataManager.DBHelper.GetConnection(DBHelper.DEFAULT);
                        DbTransaction trans = conn.BeginTransaction();

                        try
                        {
                            foreach (string op in opArray)
                            {
                                if (string.IsNullOrEmpty(op))
                                    continue;

                                // 登录符合配置的OP条件的所有Stn
                                OPCfg opCfg = lineData.RunningData.OPDatas.Keys.FirstOrDefault(o => o.OP == op);
                                OPRunningData opData = lineData.RunningData.OPDatas[opCfg];
                                if (opData != null && opData.StnDatas != null)
                                {
                                    foreach (StnRunningData stnData in opData.StnDatas.Values.ToArray())
                                    {
                                        if (stnData != null && stnData.StnCfg != null)
                                        {
                                            stnData.Operator = operatorId;

                                            uint currentLoginCnt = 0;
                                            uint stnLoginLimit = stnData.StnCfg.OprLogonLimit;

                                            stations.Add(new ClientStnCfg()
                                            {
                                                Line = lineData.Line,
                                                OP = opCfg.OP,
                                                STN = stnData.StnCfg.Name,
                                                Description = stnData.StnCfg.Name,
                                                Sequence = opCfg.Sequence,
                                                Operators = null
                                            });

                                            dt = DataManager.DBHelper.Query(trans, string.Format("select count(*) from ACC_Operator_Status where Line='{0}' and OP='{1}' and Stn='{2}'",
                                                lineData.Line, op, stnData.StnCfg.Name));
                                            if (dt != null && dt.Rows.Count > 0)
                                            {
                                                uint.TryParse(dt.Rows[0][0].ToString(), out currentLoginCnt);
                                                if (currentLoginCnt >= stnLoginLimit) // 超过最大同时登录数限制
                                                {
                                                    // 查找该工位最早登录记录
                                                    dt = DataManager.DBHelper.Query(trans, string.Format("select OperatorID from ACC_Operator_Status where Line='{0}' and OP='{1}' and Stn='{2}' order by CTime",
                                                        lineData.Line, op, stnData.StnCfg.Name));
                                                    if (dt != null && dt.Rows.Count > 0)
                                                    {
                                                        // 获取最早登录记录的OperatorID，用于删除和插入His表
                                                        string operatorID = dt.Rows[0]["OperatorID"].ToString();

                                                        // 删除该工位最早的登录记录
                                                        DataManager.DBHelper.Update(trans, string.Format("delete from ACC_Operator_Status where Line='{0}' and OP='{1}' and Stn='{2}' and OperatorID='{3}'",
                                                            lineData.Line, op, stnData.StnCfg.Name, operatorId));

                                                        // 插入登出信息到His表，强制登出
                                                        DataManager.DBHelper.Update(trans, string.Format("Insert into ACC_Operator_Login_His(OperatorID, Line, OP, STN, Type, CTime) values('{0}', '{1}', '{2}', '{3}', '{4}', '{5}')",
                                                            operatorId, lineData.Line, op, stnData.StnCfg.Name, "2", ctime.ToString("yyyy-MM-dd HH:mm:ss")));
                                                    }
                                                }
                                            }

                                            dt = DataManager.DBHelper.Query(trans, string.Format("select * from ACC_Operator_Status where Line='{0}' and OP='{1}' and Stn='{2}' and OperatorID='{3}'",
                                                lineData.Line, op, stnData.StnCfg.Name, operatorId));
                                            if (dt != null && dt.Rows.Count > 0)
                                            {
                                                // 删除该卡号登录记录
                                                DataManager.DBHelper.Update(trans, string.Format("delete from ACC_Operator_Status where Line='{0}' and OP='{1}' and Stn='{2}' and OperatorID='{3}'",
                                                    lineData.Line, op, stnData.StnCfg.Name, operatorId));

                                                // 插入登出信息到His表，强制登出
                                                DataManager.DBHelper.Update(trans, string.Format("Insert into ACC_Operator_Login_His(OperatorID, Line, OP, STN, Type, CTime) values('{0}', '{1}', '{2}', '{3}', '{4}', '{5}')",
                                                    operatorId, lineData.Line, op, stnData.StnCfg.Name, "2", ctime.ToString("yyyy-MM-dd HH:mm:ss")));
                                            }

                                            // 插入当前登录用户信息
                                            DataManager.DBHelper.Update(trans, string.Format("Insert into ACC_Operator_Status(Line, OP, STN, OperatorID, CTime) values('{0}', '{1}', '{2}', '{3}', '{4}')",
                                                lineData.Line, op, stnData.StnCfg.Name, operatorId, ctime.ToString("yyyy-MM-dd HH:mm:ss")));

                                            // 插入His
                                            DataManager.DBHelper.Update(trans, string.Format("Insert into ACC_Operator_Login_His(OperatorID, Line, OP, STN, Type, CTime) values('{0}', '{1}', '{2}', '{3}', '{4}', '{5}')",
                                                operatorId, lineData.Line, op, stnData.StnCfg.Name, "0", ctime.ToString("yyyy-MM-dd HH:mm:ss")));

                                        }
                                    }
                                }
                            }

                            trans.Commit();
                        }
                        catch (Exception ex)
                        {
                            trans.Rollback();
                            clientResponse.Result = false;
                            clientResponse.Message = msg = "Login failed, " + ex.Message;
                        }
                        finally
                        {
                            if (conn != null && conn.State == ConnectionState.Open)
                            {
                                conn.Close();
                            }
                            conn = null;
                        }
                    }
                }
                else
                {
                    clientResponse.Result = false;
                    clientResponse.Message = msg = "Login failed, no right to any OP";
                }

                clientResponse.Data = new ClientLoginResult() { Line = lineData.Line, Operator = clientOperator, Stations = stations };
            }

            return msg;
        }

        protected virtual string DoLogout(LineData lineData, string operatorId, ref ClientResponse clientResponse)
        {
            string msg = string.Empty;
            DateTime ctime = DateTime.Now;

            System.Data.DataTable dt = DataManager.DBHelper.Query(string.Format("SELECT * FROM ACC_OPERATOR WHERE LINE = '{0}' AND OPERATORID = '{1}' AND ENABLE = '1'", lineData.Line, operatorId));
            if (null != dt && dt.Rows.Count > 0)
            {
                ClientOperator clientOperator = new ClientOperator()
                {
                    OperatorId = operatorId,
                    Name = dt.Rows[0]["NAME"].ToString(),
                    LogoutTime = ctime.ToString("yyyy-MM-dd HH:mm:ss")
                };
                string ops = dt.Rows[0]["OP"].ToString();

                if (!string.IsNullOrEmpty(ops))
                {
                    string[] opArray = ops.Split(new char[] { ';' });
                    if (opArray != null && opArray.Length > 0)
                    {
                        DbConnection conn = DataManager.DBHelper.GetConnection(DBHelper.DEFAULT);
                        DbTransaction trans = conn.BeginTransaction();
                        try
                        {
                            foreach (string op in opArray)
                            {
                                // 登录符合配置的OP条件的所有Stn
                                OPCfg opCfg = lineData.RunningData.OPDatas.Keys.First(o => o.OP == op);
                                OPRunningData opData = lineData.RunningData.OPDatas[opCfg];
                                if (opData != null && opData.StnDatas != null)
                                {
                                    foreach (StnRunningData stnData in opData.StnDatas.Values)
                                    {
                                        if (stnData != null && stnData.StnCfg != null)
                                        {
                                            stnData.Operator = "";
                                            string durationMinutes = "0";
                                            // 查找该工位最早登录记录
                                            dt = DataManager.DBHelper.Query(trans, string.Format("select CTime from ACC_Operator_Status where Line='{0}' and OP='{1}' and Stn='{2}' and OperatorID='{3}' order by CTime",
                                                lineData.Line, op, stnData.StnCfg.Name, operatorId));
                                            if (dt != null && dt.Rows.Count > 0)
                                            {
                                                // 获取该员工的登录时间，用于返回给客户端
                                                DateTime loginTime = (DateTime)dt.Rows[0]["CTime"];
                                                clientOperator.LoginTime = loginTime.ToString("yyyy-MM-dd HH:mm:ss");
                                                // 删除该工位最早的登录记录
                                                DataManager.DBHelper.Update(trans, string.Format("delete from ACC_Operator_Status where Line='{0}' and OP='{1}' and Stn='{2}' and OperatorID='{3}'",
                                                    lineData.Line, op, stnData.StnCfg.Name, operatorId));

                                                //获取登录时长 Add by Alpha 2016-11-21
                                                durationMinutes = (new TimeSpan(loginTime.Ticks)).Subtract(new TimeSpan(ctime.Ticks)).TotalMinutes.ToString();
                                            }

                                            // 插入登出信息到His表，正常登出
                                            DataManager.DBHelper.Update(trans, string.Format("Insert into ACC_Operator_Login_His(OperatorID, Line, OP, STN, Type, CTime, TimeDuration) values('{0}', '{1}', '{2}', '{3}', '{4}', '{5}', '{6}')",
                                                operatorId, lineData.Line, op, stnData.StnCfg.Name, "1", ctime.ToString("yyyy-MM-dd HH:mm:ss"), durationMinutes));
                                        }
                                    }
                                }
                            }

                            trans.Commit();
                        }
                        catch (Exception ex)
                        {
                            trans.Rollback();
                            clientResponse.Result = false;
                            clientResponse.Message = msg = "Logout failed, " + ex.Message;
                        }
                        finally
                        {
                            if (conn != null && conn.State == ConnectionState.Open)
                            {
                                conn.Close();
                            }
                            conn = null;
                        }
                    }
                }

                clientResponse.Data = new ClientLoginResult() { Line = lineData.Line, Operator = clientOperator };
            }
            else
            {
                clientResponse.Result = false;
                clientResponse.Message = msg = "Logout failed, cannot find operator";
            }

            return msg;
        }

        protected virtual string DoLogoutAll(LineData lineData, string operatorId, ref ClientResponse clientResponse)
        {
            string msg = string.Empty;
            DateTime ctime = DateTime.Now;

            string sql = "SELECT DISTINCT PRIVID FROM ACC_PRIVILEGES_ROLE WHERE PRIVID = 990101 AND ROLEID IN (SELECT DISTINCT ROLEID FROM ACC_ROLE_USER WHERE USERID IN (SELECT USERID FROM ACC_USER WHERE OPERATORID = '" + operatorId + "'))";
            DataTable dtRole = DataManager.DBHelper.Query(sql);
            if (dtRole == null || dtRole.Rows.Count <= 0)
            {
                clientResponse.Result = false;
                clientResponse.Message = msg = "logout all failed, no right";
            }
            else
            {
                DbConnection conn = DataManager.DBHelper.GetConnection(DBHelper.DEFAULT);
                DbTransaction trans = conn.BeginTransaction();
                try
                {
                    // 获取当前改线登录的所有登录信息
                    DataTable dt = DataManager.DBHelper.Query(trans, string.Format("select OperatorID, OP, STN from ACC_Operator_Status where Line='{0}'", lineData.Line));
                    if (dt != null && dt.Rows.Count > 0)
                    {
                        foreach (DataRow row in dt.Rows)
                        {
                            string operatorID = row["OperatorID"].ToString();
                            string op = row["OP"].ToString();
                            string stn = row["STN"].ToString();

                            // 清除ACC内存登录信息
                            StnCfg stnCfg = lineData.RunningData.StnDatas.Keys.First(o => o.Name == stn && o.OPCfg.OP == op);
                            StnRunningData stnData = lineData.RunningData.StnDatas[stnCfg];
                            if (stnData != null)
                                stnData.Operator = "";

                            // 插入登出信息到His表，强制登出
                            DataManager.DBHelper.Update(trans, "Insert into ACC_Operator_Login_His(OperatorID, Line, OP, STN, Type, CTime) values('{0}', '{1}', '{2}', '{3}', '{4}', '{5}')",
                                operatorID, lineData.Line, op, stn, "2", ctime.ToString("yyyy-MM-dd HH:mm:ss"));
                        }

                        // 清空改线当前登录信息
                        DataManager.DBHelper.Update(trans, string.Format("delete from ACC_Operator_Status where Line='{0}'", lineData.Line));
                    }

                    trans.Commit();
                }
                catch (Exception e)
                {
                    trans.Rollback();

                    clientResponse.Result = false;
                    clientResponse.Message = msg = "logout all failed, " + e.Message;
                }
                finally
                {
                    if (conn != null && conn.State == ConnectionState.Open)
                    {
                        conn.Close();
                    }
                    conn = null;
                }
            }

            return msg;
        }
        #endregion

        #region PreLoad:校验条码
        //protected virtual string DoPreLoad(StnRunningData stnData, uint partTypeId, String[] barcodes, string idname, ref ClientResponse clientResponse)
        //{
        //    string msg = string.Empty;
        //    string unitSN = string.Empty;
        //    string componetSN = string.Empty;

        //    if (barcodes == null || barcodes.Length < 1)
        //    {
        //        clientResponse.Result = false;
        //        clientResponse.Message = msg = "There is no any Barcode";
        //        return msg;
        //    }

        //    if (!string.IsNullOrEmpty(idname) && barcodes.Length < 2)
        //    {
        //        clientResponse.Result = false;
        //        clientResponse.Message = msg = "Barcode count not enough";
        //        return msg;
        //    }

        //    if (stnData.PartNo == null)
        //    {
        //        clientResponse.Result = false;
        //        clientResponse.Message = msg = "PartNo Not Start in ACC";
        //        return msg;
        //    }

        //    if (!stnData.PartNo.BomCfg.PartTypeID.Equals(partTypeId))
        //    {
        //        clientResponse.Result = false;
        //        clientResponse.Message = msg = "PartNo Not Match";
        //        return msg;
        //    }

        //    unitSN = barcodes[0];
        //    componetSN = barcodes.Length > 1 ? barcodes[1] : string.Empty;

        //    LineData lineData = stnData.StnCfg.LineCfg.LineData;
        //    StnProcess stnProcess = LineManager.Lines[lineData.Line].StnProcesses[stnData.StnCfg];
        //    MethodInfo method = stnProcess.GetType().GetMethod("PreLoadCheck");

        //    if (method == null)
        //    {
        //        if (!string.IsNullOrEmpty(idname) && barcodes.Length < 2)
        //        {
        //            clientResponse.Result = false;
        //            clientResponse.Message = msg = "STN don't implement PreLoadCheck Feature";
        //            return msg;
        //        }
        //    }

        //    object[] param = new object[] 
        //        {
        //            unitSN,
        //            componetSN,
        //            idname,
        //            msg
        //        };
        //    clientResponse.Result = (bool)method.Invoke(stnProcess, param);
        //    clientResponse.Message = msg = param[3].ToString();
        //    return msg;
        //}

        protected virtual string DoPreLoad(StnRunningData stnData, uint partTypeId, String[] barcodes, string idname, ref ClientResponse clientResponse)
        {
            string msg = string.Empty;
            string unitSN = string.Empty;

            List<String> lstComps = new List<string>();

            if (barcodes != null && barcodes.Length > 0)
            {
                unitSN = barcodes[0];
                for (int i = 1; i < barcodes.Length; ++i)
                {
                    lstComps.Add(barcodes[i]);
                }
            }

            ACCDevice.NextStepParam nextStepParam = new ACCDevice.NextStepParam();
            nextStepParam.UnitSN = unitSN;
            nextStepParam.ComponentSN = lstComps.ToArray();
            nextStepParam.PartTypeID = (int)partTypeId;
            LineData lineData = stnData.StnCfg.LineCfg.LineData;
            BomCfg bomCfg = lineData.Cfg.BomCfgByID[partTypeId];
            if (null != bomCfg)
                nextStepParam.PartNo = lineData.RunningData.RunningPartNos[bomCfg.PartNo];

            StnProcess stnProcess = LineManager.Lines[stnData.StnCfg.LineCfg.Line].StnProcesses[stnData.StnCfg];
            (stnProcess.Device as ClientCommonDevice).LastNextStepParam = nextStepParam;
            stnProcess.OnNextStep(stnProcess.Device);

            ACCDevice.NextStepResult nextStepResult = (stnProcess.Device as ClientCommonDevice).LastNextStepResult;
            if (nextStepResult == null || nextStepResult.ErrorCode != ACCCode.ACCOK)
            {
                clientResponse.Result = false;
                clientResponse.Message = msg = (nextStepResult == null) ? "NextStep检查处理失败" : nextStepResult.ErrorMessage;
            }
            else
            {
                if (nextStepResult.OP != stnData.StnCfg.OPCfg.OP)
                {
                    clientResponse.Result = false;
                    clientResponse.Message = msg = string.Format("工件应在工位{0}", nextStepResult.OP);
                }
                List<String> lstComps_1 = new List<string>();
                string[] barcode = nextStepResult.ErrorMessage.Split(',');

                if (barcode.Length > 1)
                {
                    for (int i = barcode.Length; i > 0; i--)
                    {
                        lstComps_1.Add(barcode[i - 1]);
                    }
                    nextStepResult.ErrorMessage = "";
                    clientResponse.Data = lstComps_1;
                }
            }

            return string.Empty;
        }
        #endregion

        #region NextStep

        protected virtual string DoNextStep(StnRunningData stnData, uint partTypeId, String[] barcodes, ref ClientResponse clientResponse)
        {
            string msg = string.Empty;
            string unitSN = string.Empty;
            List<String> lstComps = new List<string>();

            if (barcodes != null && barcodes.Length > 0)
            {
                unitSN = barcodes[barcodes.Length - 1];
                for (int i = 0; i < barcodes.Length - 1; ++i)
                {
                    lstComps.Add(barcodes[i]);
                }
            }

            ACCDevice.NextStepParam nextStepParam = new ACCDevice.NextStepParam();
            nextStepParam.UnitSN = unitSN;
            nextStepParam.ComponentSN = lstComps.ToArray();
            nextStepParam.PartTypeID = (int)partTypeId;
            LineData lineData = stnData.StnCfg.LineCfg.LineData;
            BomCfg bomCfg = lineData.Cfg.BomCfgByID[partTypeId];
            if (null != bomCfg)
                nextStepParam.PartNo = lineData.RunningData.RunningPartNos[bomCfg.PartNo];

            StnProcess stnProcess = LineManager.Lines[lineData.Line].StnProcesses[stnData.StnCfg];

            (stnProcess.Device as ClientCommonDevice).LastNextStepParam = nextStepParam;
            stnProcess.OnNextStep(stnProcess.Device);

            ACCDevice.NextStepResult nextStepResult = (stnProcess.Device as ClientCommonDevice).LastNextStepResult;
            if (nextStepResult == null || nextStepResult.ErrorCode != ACCCode.ACCOK)
            {
                clientResponse.Result = false;
                clientResponse.Message = msg = (nextStepResult == null) ? "NextStep检查处理失败" : nextStepResult.ErrorMessage;
            }
            else
            {
                if (nextStepResult.OP != stnData.StnCfg.OPCfg.OP)
                {
                    clientResponse.Result = false;
                    clientResponse.Message = msg = string.Format("工件应在工位{0}", nextStepResult.OP);
                }
            }

            return msg;
        }

        #endregion

        #region Load处理
        protected virtual string DoLoad(StnRunningData stnData, uint partTypeId, String[] barcodes, ref ClientResponse clientResponse)
        {
            string msg = string.Empty;
            string unitSN = string.Empty;

            List<String> lstComps = new List<string>();

            if (barcodes != null && barcodes.Length > 0)
            {
                unitSN = barcodes[0];
                for (int i = 1; i < barcodes.Length; ++i)
                {
                    lstComps.Add(barcodes[i]);
                }
            }

            ACCDevice.LoadParam loadParam = new ACCDevice.LoadParam();
            loadParam.UnitSN = unitSN;
            loadParam.ComponentSN = lstComps.ToArray();
            loadParam.PartTypeID = (int)partTypeId;
            LineData lineData = stnData.StnCfg.LineCfg.LineData;
            BomCfg bomCfg = lineData.Cfg.BomCfgByID[partTypeId];
            if (null != bomCfg)
                loadParam.PartNo = lineData.RunningData.RunningPartNos[bomCfg.PartNo];

            StnProcess stnProcess = LineManager.Lines[lineData.Line].StnProcesses[stnData.StnCfg];
            (stnProcess.Device as ClientCommonDevice).LastLoadParam = loadParam;
            stnProcess.OnLoad(stnProcess.Device);

            ACCDevice.LoadResult loadResult = (stnProcess.Device as ClientCommonDevice).LastLoadResult;
            if (loadResult == null || loadResult.ErrorCode != ACCCode.ACCOK)
            {
                clientResponse.Result = false;
                clientResponse.Message = msg = loadResult == null ? "Load处理失败" : loadResult.ErrorMsg;
            }
            else
            {
                Dictionary<string, object> clientLoadResult = new Dictionary<string, object>();
                clientLoadResult.Add("CycleId", loadResult.CycleID);
                clientLoadResult.Add("Action", (int)loadResult.Action);
                clientLoadResult.Add("IsRework", (bool)loadResult.IsRework);
                clientLoadResult.Add("StatusBits", loadResult.StatusBit);
                clientLoadResult.Add("UnitParttypeID", (stnData.LastTryLoadUnit != null && stnData.LastTryLoadUnit.RunningPartNo != null) ? stnData.LastTryLoadUnit.RunningPartNo.BomCfg.PartTypeID : 0);
                clientLoadResult.Add("IsTestUnit", (stnData.LastTryLoadUnit != null) ? stnData.LastTryLoadUnit.GetTagValue("IsTestUnit") : 0);

                clientResponse.Data = clientLoadResult;
            }

            return msg;
        }
        #endregion

        #region Unload 处理
        protected virtual string DoUnload(StnRunningData stnData, uint partTypeId, String[] barcodes, int statusBits, int failureBits, List<ClientProcData> lstProcDatas, ref ClientResponse clientResponse)
        {
            string msg = string.Empty;
            string unitSN = string.Empty;

            List<String> lstComps = new List<string>();

            if (barcodes != null && barcodes.Length > 0)
            {
                unitSN = barcodes[0];
                for (int i = 1; i < barcodes.Length; ++i)
                {
                    lstComps.Add(barcodes[i]);
                }
            }

            ACCDevice.UnloadParam unloadParam = new ACCDevice.UnloadParam();
            unloadParam.UnitSN = unitSN;
            unloadParam.ComponentSN = lstComps.ToArray();
            unloadParam.StatusBits = (uint)statusBits;
            unloadParam.IsOk = (statusBits & 0x01) == 1;
            unloadParam.FailureBits = (uint)failureBits;
            unloadParam.PartTypeID = (int)partTypeId;

            LineData lineData = stnData.StnCfg.LineCfg.LineData;
            BomCfg bomCfg = lineData.Cfg.BomCfgByID[partTypeId];
            if (null != bomCfg)
            {
                unloadParam.PartNo = lineData.RunningData.RunningPartNos[bomCfg.PartNo];

                GetUnloadRealCfg(stnData, lstProcDatas, bomCfg, ref unloadParam);
            }
            StnProcess stnProcess = LineManager.Lines[lineData.Line].StnProcesses[stnData.StnCfg];
            (stnProcess.Device as ClientCommonDevice).LastUnloadParam = unloadParam;
            stnProcess.OnUnload(stnProcess.Device);
            ACCDevice.UnloadResult unloadResult = (stnProcess.Device as ClientCommonDevice).LastUnloadResult;
            if (unloadResult == null || unloadResult.ErrorCode != ACCCode.ACCOK)
            {
                clientResponse.Result = false;
                clientResponse.Message = msg = unloadResult == null ? "Unload处理失败" : unloadResult.ErrorMessage;
            }

            if (unloadResult != null && unloadResult.ErrorCode == ACCCode.ACCOK)
            {
                string[] count = unloadResult.ErrorMessage.Split(';');

                if (count.Length > 1)
                {
                    ProductCount productcount = new ProductCount();
                    productcount.OK_COUNT = int.Parse(count[0]);
                    productcount.NOK_COUNT = int.Parse(count[1]);
                    productcount.SCARP_COUNT = int.Parse(count[2]);
                    productcount.PENDING_COUNT = int.Parse(count[3]);
                    clientResponse.Data = productcount;
                    msg = string.Empty;
                }
                else
                {
                    msg = string.Empty;
                }
            }

            // unload结束后、把最新的物料信息反馈给客户端
            clientResponse.Data = stnProcess.GetComponentSet(false);

            return msg;
        }

        protected virtual void GetUnloadRealCfg(StnRunningData stnData, List<ClientProcData> lstProcDatas, BomCfg bomCfg, ref ACCDevice.UnloadParam unloadParam)
        {
            if (unloadParam.N_Real == null)
                unloadParam.N_Real = new DictionaryEx<string, ACCDevice.ProcDataValue>();
            if (unloadParam.N_String == null)
                unloadParam.N_String = new DictionaryEx<string, ACCDevice.ProcDataValue>();

            if (lstProcDatas == null)
                return;

            foreach (ClientProcData procData in lstProcDatas)
            {
                ProcDataCfg procDataCfg = stnData.StnCfg.StnPLCProcDataCfg[bomCfg][procData.Name];
                if (procDataCfg != null)
                {
                    if (REAL_PATTERN.IsMatch(procDataCfg.PLC_Tag) || INT_PATTERN.IsMatch(procDataCfg.PLC_Tag) || BOOL_PATTERN.IsMatch(procDataCfg.PLC_Tag))
                    {
                        unloadParam.N_Real.Add(procDataCfg.PLC_Tag, new ACCDevice.ProcDataValue()
                        {
                            value = (procData.Value == null) ? 0 : double.Parse(procData.Value.ToString()),
                            DataCfgName = procDataCfg.Name,
                            DataCfgRecID = procDataCfg.Rec_ID,
                            HasLowLimit = procDataCfg.hasUpLimit,
                            HasUpLimit = procDataCfg.hasUpLimit,
                            Low_DataID = procDataCfg.Low_DataID,
                            LowLimit = procDataCfg.Low_Limit,
                            UpLimit = procDataCfg.Up_Limit,
                            str_value = ""
                        });
                    }
                    if (STRING_PATTERN.IsMatch(procDataCfg.PLC_Tag))
                    {
                        unloadParam.N_String.Add(procDataCfg.PLC_Tag, new ACCDevice.ProcDataValue()
                        {
                            value = 0,
                            DataCfgName = procDataCfg.Name,
                            DataCfgRecID = procDataCfg.Rec_ID,
                            HasLowLimit = procDataCfg.hasUpLimit,
                            HasUpLimit = procDataCfg.hasUpLimit,
                            Low_DataID = procDataCfg.Low_DataID,
                            LowLimit = procDataCfg.Low_Limit,
                            UpLimit = procDataCfg.Up_Limit,
                            str_value = procData.Value == null ? "" : procData.Value.ToString()
                        });
                    }
                }
            }
        }

        //protected double GetLimitValueWithPLCAddress(StnRunningData stnData, string station, string plcAddress)
        //{
        //    plcAddress = plcAddress.ToUpper();
        //    StnCfg stn = stnData.StnCfg.LineCfg.LineData.Cfg.StnCfg[station];
        //    if (stn == null)
        //    {
        //        return 0;
        //    }
        //    DictionaryEx<int, PartTyeDataCfg> datas = stn.PartTypeData[stnData.PartNo.BomCfg.PartNo];
        //    if (datas == null)
        //    {
        //        return 0;
        //    }
        //    Match match;
        //    int num;
        //    Regex regex = null;
        //    PartTyeDataCfg.PartTyeDataValueType type;
        //    if (plcAddress.IndexOf("INT") != -1)
        //    {
        //        type = PartTyeDataCfg.PartTyeDataValueType.PLC_INT;
        //        regex = INT_PATTERN;
        //    }
        //    else if (plcAddress.IndexOf("REAL") != -1)
        //    {
        //        type = PartTyeDataCfg.PartTyeDataValueType.PLC_REAL;
        //        regex = REAL_PATTERN;
        //    }
        //    else
        //    {
        //        return 0;
        //    }
        //    match = regex.Match(plcAddress);
        //    if (match.Success)
        //    {
        //        num = int.Parse(match.Groups[1].Value);
        //    }
        //    else
        //    {
        //        return 0;
        //    }
        //    object value = null;
        //    foreach (PartTyeDataCfg cfg in datas.Values)
        //    {
        //        if (cfg.ValueType != type)
        //        {
        //            continue;
        //        }
        //        match = regex.Match(cfg.Address.ToUpper());
        //        if (match.Success)
        //        {
        //            if (num == int.Parse(match.Groups[1].Value))
        //            {
        //                value = cfg.Value;
        //            }
        //        }
        //    }
        //    if (value == null)
        //    {
        //        return 0;
        //    }
        //    else
        //    {
        //        return (double)value;
        //    }
        //}
        #endregion

        #region 打印
        protected virtual string DoPrint(StnRunningData stnData, ref ClientResponse clientResponse)
        {
            string msg = string.Empty;

            LineData lineData = stnData.StnCfg.LineCfg.LineData;
            StnProcess stnProcess = LineManager.Lines[lineData.Line].StnProcesses[stnData.StnCfg];
            stnProcess.OnPrintLabel(stnProcess.Device);

            ACCDevice.PrintResult printResult = (stnProcess.Device as ClientCommonDevice).LastPrintResult;
            if (printResult == null || printResult.ErrorCode != ACCCode.ACCOK)
            {
                clientResponse.Result = false;
                clientResponse.Message = msg = printResult == null ? "Print处理失败" : printResult.ErrorMessage;
            }
            else
            {
                List<BarCodeList> lstComps_1 = new List<BarCodeList>();
                string[] barcode = printResult.ErrorMessage.Split(',');

                if (barcode.Length > 1)
                {
                    for (int i = 0; i < barcode.Length - 1; i++)
                    {
                        lstComps_1.Add(new BarCodeList() { Area = (i + 1), Barcode = barcode[i] });
                    }
                    printResult.ErrorMessage = "";
                    clientResponse.Data = lstComps_1;
                }
                else
                {
                    lstComps_1.Add(new BarCodeList() { Area = 0, Barcode = barcode[0] });
                    clientResponse.Data = lstComps_1;
                }
                //clientResponse.Data = printResult.ErrorMessage;
                printResult.ErrorMessage = string.Empty;
            }

            return msg;
        }
        #endregion

        #region 物料处理
        protected static string SQL_BIN_DELETE = "DELETE FROM ACC_Material_Bin WHERE Bin='{0}'";
        protected static string SQL_BIN_INSERT = "INSERT INTO ACC_Material_Bin(ItemPartNo, ItemRev, Bin, Lot, SLot, Qty, USN, CTime) VALUES('{0}', '{1}', '{2}', '{3}', '{4}', {5}, '{6}', '{7}')";
        protected static string SQL_BIN_SELECT = "SELECT * FROM ACC_Material_Bin WHERE BIN='{0}'";

        protected virtual string DoBin(ClientRequest clientRequest, List<ClientLotTrackItem> lstLotItems, ref ClientResponse clientResponse)
        {
            string msg = string.Empty;

            #region 参数检查
            if (lstLotItems == null || lstLotItems.Count <= 0)
            {
                clientResponse.Result = false;
                return clientResponse.Message = msg = "不能为空物料";
            }

            string bin = string.Empty;
            foreach (ClientLotTrackItem item in lstLotItems)
            {
                if (item == null)
                {
                    logger.Debug("参数不能转换");
                    continue;
                }

                double nQty;
                double.TryParse(string.IsNullOrEmpty(item.Qty) ? "0" : item.Qty, out nQty);
                if (nQty <= 0)
                    msg = "数量应大于0";
                else if (string.IsNullOrEmpty(item.ItemPartNo))
                    msg = "物料号不能为空";
                else if (string.IsNullOrEmpty(item.Lot))
                    msg = "物料批次号不能为空";
                else if (string.IsNullOrEmpty(item.Bin))
                    msg = "箱号不能为空";

                if (!string.IsNullOrEmpty(msg))
                {
                    clientResponse.Result = false;
                    return clientResponse.Message = msg;
                }

                bin = item.Bin;
            }
            #endregion

            #region 物料和箱号对应关系保存
            var conn = ACC.Data.DataManager.DBHelper.GetConnection(ACC.Util.DB.DBHelper.DEFAULT);
            var trans = conn.BeginTransaction();

            try
            {
                DataManager.DBHelper.Update(trans, string.Format(SQL_BIN_DELETE, bin));
                foreach (ClientLotTrackItem item in lstLotItems)
                {
                    if (item == null) continue;

                    DataManager.DBHelper.Update(trans, string.Format(SQL_BIN_INSERT, item.ItemPartNo, item.ItemRev, item.Bin, item.Lot, item.SLot, item.Qty, item.USN, DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")));
                }

                clientResponse.Result = true;
                clientResponse.Message = msg = string.Empty;
                trans.Commit();
            }
            catch (Exception ex)
            {
                trans.Rollback();
                clientResponse.Result = false;
                clientResponse.Message = msg = ex.Message;
                logger.Debug(ex.Message + "\r\n" + ex.StackTrace);
            }
            finally
            {
                if (conn != null && conn.State == System.Data.ConnectionState.Open)
                {
                    conn.Close();
                }
                conn = null;
            }
            #endregion

            return msg;
        }

        protected virtual string DoBinLot(StnRunningData stnData, ClientRequest clientRequest, ref ClientResponse clientResponse)
        {
            string msg = string.Empty;

            String bin = clientRequest.Parameters.ContainsKey("Bin") ? clientRequest.Parameters["Bin"].ToString() : "";

            if (string.IsNullOrEmpty(bin))
                msg = "箱号不能为空";

            if (!string.IsNullOrEmpty(msg))
            {
                clientResponse.Result = false;
                clientResponse.Message = msg;
            }
            else
            {
                try
                {
                    var dt = DataManager.DBHelper.Query(string.Format(SQL_BIN_SELECT, bin));
                    if (dt != null && dt.Rows.Count > 0)
                    {
                        List<ACCDevice.LotChangeData> datas = new List<ACCDevice.LotChangeData>();
                        List<ClientLotTrackItem> lotTrackItems = new List<ClientLotTrackItem>();
                        foreach (DataRow row in dt.Rows)
                        {
                            String itemPartNo = row["ItemPartNo"].ToString();
                            String sLot = row["SLot"] == null ? "" : dt.Rows[0]["SLot"].ToString();
                            String usn = row["USN"] == null ? "" : dt.Rows[0]["USN"].ToString();
                            String lot = row["Lot"].ToString();
                            String qty = row["Qty"].ToString();
                            BomCfg.OPBomCfg opBomCfg = (stnData.PartNo == null ||
                                                        stnData.PartNo.BomCfg == null ||
                                                        stnData.PartNo.BomCfg.BomItemCfg == null ||
                                                        stnData.StnCfg == null)
                                                        ? null : stnData.PartNo.BomCfg.BomItemCfg[stnData.StnCfg.OPCfg];
                            if (opBomCfg != null && opBomCfg.BomItem.ContainsKey(itemPartNo))
                            {
                                BomItemCfg bomItemCfg = opBomCfg.BomItem[itemPartNo];
                                datas.Add(new ACCDevice.LotChangeData()
                                                {
                                                    ItemPartNo = "P" + itemPartNo,
                                                    Lot = "1T" + lot,
                                                    Qty = "Q" + qty,
                                                    SLot = sLot,
                                                    BomItem = bomItemCfg,
                                                    ItemRev = "2P" + bomItemCfg.ItemRev,
                                                    FeederNo = bomItemCfg.FeederNo,
                                                    QtyPer = bomItemCfg.QtyPer,
                                                    Reserved1 = usn
                                                });
                                lotTrackItems.Add(new ClientLotTrackItem() { ItemPartNo = itemPartNo, ItemRev = bomItemCfg.ItemRev, Lot = lot, SLot = sLot, FeederNo = bomItemCfg.FeederNo, Qty = qty, USN = usn });
                            }
                            else
                            {
                                clientResponse.Result = false;
                                clientResponse.Message = msg = "物料号" + itemPartNo + "在ACC系统BOM中不存在";
                                break;
                            }
                        }

                        if (clientResponse.Result)
                        {
                            LineData lineData = stnData.StnCfg.LineCfg.LineData;
                            StnProcess stnProcess = LineManager.Lines[lineData.Line].StnProcesses[stnData.StnCfg];
                            stnProcess.Device.SetLotChangeData(datas);
                            stnProcess.OnLotChange(stnProcess.Device);

                            ACCDevice.LotChangeResult lotChgResult = stnProcess.Device.GetLotChangeResult();

                            clientResponse.Result = lotChgResult.ErrorCode == ACCCode.ACCOK;
                            if (lotChgResult.ErrorCode != ACCCode.ACCOK)
                            {
                                clientResponse.Message = msg = "扫料失败";
                            }
                            else
                            {
                                clientResponse.Data = lotTrackItems;
                                //扫描成功后删除Bin与物料的关系
                                DataManager.DBHelper.Update(string.Format(SQL_BIN_DELETE, bin));
                            }
                        }
                    }
                    else
                    {
                        clientResponse.Result = false;
                        clientResponse.Message = msg = "箱号" + bin + "找不到绑定的物料批次";
                    }
                }
                catch (Exception ex)
                {
                    clientResponse.Result = false;
                    clientResponse.Message = msg = ex.Message;
                    logger.Debug(ex.Message + "\r\n" + ex.StackTrace);
                }
            }

            return msg;
        }

        protected virtual string DoLot(StnRunningData stnData, ClientRequest clientRequest, ref ClientResponse clientResponse)
        {
            string msg = string.Empty;

            String itemPartNo = clientRequest.Parameters.ContainsKey("ItemPartNo") ? clientRequest.Parameters["ItemPartNo"].ToString() : "";
            String lot = clientRequest.Parameters.ContainsKey("Lot") ? clientRequest.Parameters["Lot"].ToString() : "";
            String usn = clientRequest.Parameters.ContainsKey("USN") ? clientRequest.Parameters["USN"].ToString() : "";
            String sLot = clientRequest.Parameters.ContainsKey("SLot") ? clientRequest.Parameters["SLot"].ToString() : "";
            String qty = clientRequest.Parameters.ContainsKey("Qty") ? clientRequest.Parameters["Qty"].ToString() : "0";
            double nQty;
            double.TryParse(qty, out nQty);
            if (nQty <= 0)
                msg = "数量应大于0";
            else if (string.IsNullOrEmpty(itemPartNo))
                msg = "物料号不能为空";
            else if (string.IsNullOrEmpty(lot))
                msg = "物料批次号不能为空";

            if (!string.IsNullOrEmpty(msg))
            {
                clientResponse.Result = false;
                clientResponse.Message = msg;
            }
            else
            {
                try
                {
                    List<ACCDevice.LotChangeData> datas = new List<ACCDevice.LotChangeData>();
                    List<ClientLotTrackItem> lotTrackItems = new List<ClientLotTrackItem>();

                    BomCfg.OPBomCfg opBomCfg = stnData.PartNo.BomCfg.BomItemCfg[stnData.StnCfg.OPCfg];
                    if (opBomCfg != null && opBomCfg.BomItem.ContainsKey(itemPartNo))
                    {
                        BomItemCfg bomItemCfg = opBomCfg.BomItem[itemPartNo];
                        datas.Add(new ACCDevice.LotChangeData()
                        {
                            ItemPartNo = "P" + itemPartNo,
                            Lot = "1T" + lot,
                            Qty = "Q" + qty,
                            SLot = sLot,
                            BomItem = bomItemCfg,
                            ItemRev = "2P" + bomItemCfg.ItemRev,
                            FeederNo = bomItemCfg.FeederNo,
                            QtyPer = bomItemCfg.QtyPer,
                            Reserved1 = usn
                        });
                        lotTrackItems.Add(new ClientLotTrackItem() { ItemPartNo = itemPartNo, ItemRev = bomItemCfg.ItemRev, Lot = lot, SLot = sLot, FeederNo = bomItemCfg.FeederNo, Qty = qty });
                        LineData lineData = stnData.StnCfg.LineCfg.LineData;
                        StnProcess stnProcess = LineManager.Lines[lineData.Line].StnProcesses[stnData.StnCfg];
                        stnProcess.Device.SetLotChangeData(datas);
                        stnProcess.OnLotChange(stnProcess.Device);

                        ACCDevice.LotChangeResult lotChgResult = stnProcess.Device.GetLotChangeResult();

                        clientResponse.Result = lotChgResult.ErrorCode == ACCCode.ACCOK;
                        if (lotChgResult.ErrorCode != ACCCode.ACCOK)
                        {
                            clientResponse.Message = msg = "扫料失败";
                        }
                        else
                        {
                            clientResponse.Data = lotTrackItems;
                        }
                    }
                    else
                    {
                        clientResponse.Result = false;
                        clientResponse.Message = msg = "物料号不正确";
                    }
                }
                catch (Exception ex)
                {
                    clientResponse.Result = false;
                    clientResponse.Message = msg = ex.Message;
                    logger.Debug(ex.Message + "\r\n" + ex.StackTrace);
                }
            }

            return msg;
        }
        #endregion

        #region WorkOrder工单
        protected virtual string DoGetWorkOrder(LineData lineData, string operatorId, DateTime woDate, ref ClientResponse clientResponse)
        {
            string msg = string.Empty;

            string workOrderNo = "WO" + woDate.ToString("yyyyMMdd");
            clientResponse.Result = true;
            clientResponse.Message = msg = workOrderNo;

            string sql = "SELECT * FROM ACC_WORKORDERHEADER WHERE WONO = '" + workOrderNo + "'";
            DataTable dtWO = DataManager.DBHelper.Query(sql);
            if (dtWO != null && dtWO.Rows.Count > 0)
            {
                List<ClientWorkOrder> lstWorkOrder = new List<ClientWorkOrder>();
                foreach (DataRow row in dtWO.Rows)
                {
                    lstWorkOrder.Add(new ClientWorkOrder()
                    {
                        ID = row["ID"] is DBNull ? string.Empty : row["ID"].ToString(),
                        WONO = row["WONO"].ToString(),
                        PONO = row["PONO"].ToString(),
                        PartNo = row["PartNo"].ToString(),
                        PlanQuantity = row["PlanQuantity"].ToString(),
                        Quantity = row["Quantity"].ToString(),
                        Status = row["Status"].ToString()
                    });
                }

                clientResponse.Data = lstWorkOrder;
            }

            return msg;
        }

        protected virtual ClientWorkOrder GetWorkOrder(string wono)
        {
            string msg = string.Empty;

            string sql = "SELECT * FROM ACC_WORKORDERHEADER WHERE WONO = '" + wono + "'";
            DataTable dtWO = DataManager.DBHelper.Query(sql);
            if (dtWO != null && dtWO.Rows.Count > 0)
            {
                foreach (DataRow row in dtWO.Rows)
                {
                    return new ClientWorkOrder()
                            {
                                ID = row["ID"] is DBNull ? string.Empty : row["ID"].ToString(),
                                WONO = row["WONO"].ToString(),
                                PONO = row["PONO"].ToString(),
                                PartNo = row["PartNo"].ToString(),
                                PlanQuantity = row["PlanQuantity"].ToString(),
                                Quantity = row["Quantity"].ToString(),
                                Status = row["Status"].ToString()
                            };
                }
            }

            return null;
        }

        protected virtual ClientWorkOrder GetWorkOrder(LineData lineData)
        {
            string msg = string.Empty;

            string sql = string.Format("SELECT TOP 1 * FROM ACC_WO_WORKORDER_HEADER WHERE STATUS = 1 AND LINE = '{0}' ORDER BY SORT ", lineData.Line);
            DataTable dtWO = DataManager.DBHelper.Query(sql);
            if (dtWO != null && dtWO.Rows.Count > 0)
            {
                foreach (DataRow row in dtWO.Rows)
                {
                    return new ClientWorkOrder()
                    {
                        ID = row["ID"] is DBNull ? string.Empty : row["ID"].ToString(),
                        WONO = row["WONO"].ToString(),
                        PONO = row["PONO"].ToString(),
                        PartNo = row["PartNo"].ToString(),
                        PlanQuantity = row["PlanQuantity"].ToString(),
                        Quantity = row["Quantity"].ToString(),
                        Status = row["Status"].ToString()
                    };
                }
            }

            return null;
        }

        protected virtual ClientWorkOrder GetWorkOrderByUnitSN(string unitSN)
        {
            string msg = string.Empty;

            string sql = string.Format("SELECT b.* FROM ACC_WO_WORKORDER_DETAIL a, ACC_WO_WORKORDER_HEADER b WHERE a.WONO = b.WONO AND a.UNITSN = '{0}' ", unitSN);
            DataTable dtWO = DataManager.DBHelper.Query(sql);
            if (dtWO != null && dtWO.Rows.Count > 0)
            {
                foreach (DataRow row in dtWO.Rows)
                {
                    return new ClientWorkOrder()
                    {
                        ID = row["ID"] is DBNull ? string.Empty : row["ID"].ToString(),
                        WONO = row["WONO"].ToString(),
                        PONO = row["PONO"].ToString(),
                        PartNo = row["PartNo"].ToString(),
                        PlanQuantity = row["PlanQuantity"].ToString(),
                        Quantity = row["Quantity"].ToString(),
                        Status = row["Status"].ToString()
                    };
                }
            }

            return null;
        }

        protected virtual string DoSaveWorkOrder(LineData lineData, string operatorId, DateTime woDate, List<ClientWorkOrder> lstWorkOrder, ref ClientResponse clientResponse)
        {
            string msg = string.Empty;

            string workOrderNo = "WO" + woDate.ToString("yyyyMMdd");
            DateTime ctime = DateTime.Now;
            clientResponse.Result = true;

            foreach (ClientWorkOrder wo in lstWorkOrder)
            {
                if (wo != null)
                {
                    string sql;
                    DataTable dtWO = null;
                    if (!string.IsNullOrEmpty(wo.WONO))
                    {
                        sql = "SELECT * FROM ACC_WORKORDERHEADER WHERE WONO='{0}' AND PARTNO='{1}'";
                        sql = string.Format(sql, wo.WONO, wo.PartNo);
                        dtWO = DataManager.DBHelper.Query(sql);
                    }
                    // 新的工单计划
                    if (string.IsNullOrEmpty(wo.WONO) || dtWO == null || dtWO.Rows.Count <= 0)
                    {
                        sql = "INSERT INTO ACC_WORKORDERHEADER(ID,WONO,PARTNO,PLANQUANTITY,QUANTITY,ASI,PACKINGASI,USERNAME,CTIME,LINE) VALUES('{0}','{1}','{2}',{3},{4},'{5}','{6}','{7}','{8}','{9}')";
                        sql = string.Format(sql, ctime.ToString("yyyyMMddHHmmss"), string.IsNullOrEmpty(wo.WONO) ? workOrderNo : wo.WONO, wo.PartNo, wo.PlanQuantity, 0, "ASI", "ASI", operatorId, ctime.ToString("yyyy-MM-dd HH:mm:ss"), lineData.Line);
                        int nRet = DataManager.DBHelper.Update(sql);
                    }
                    else if (dtWO != null && dtWO.Rows.Count > 0)
                    {
                        sql = "UPDATE ACC_WORKORDERHEADER SET PLANQUANTITY={0} WHERE WONO='{1}' AND PARTNO='{2}'";
                        sql = string.Format(sql, wo.PlanQuantity, wo.WONO, wo.PartNo);
                        int nRet = DataManager.DBHelper.Update(sql);
                    }
                }
            }

            return msg;
        }

        /// <summary>
        /// 完成时一件OK的件时调用，已完成增加相应数量
        /// </summary>
        /// <param name="lineData"></param>
        /// <param name="partTypeId"></param>
        /// <param name="qtyStep"></param>
        /// <param name="clientResponse"></param>
        /// <returns></returns>
        protected virtual string DoUpdateWorkOrderQuantity(LineData lineData, uint partTypeId, int qty, ref ClientResponse clientResponse)
        {
            string msg = string.Empty;
            qty = qty < 0 ? 0 : qty;

            if (qty > 0)
            {
                string workOrderNo = "WO" + DateTime.Now.ToString("yyyyMMdd");
                DateTime ctime = DateTime.Now;
                clientResponse.Result = true;

                BomCfg bomCfg = lineData.Cfg.BomCfgByID[partTypeId];

                if (null != bomCfg)
                {
                    string sql = "UPDATE ACC_WORKORDERHEADER SET QUANTITY=QUANTITY+{0} WHERE WONO='{1}' AND PARTNO='{2}'";
                    sql = string.Format(sql, qty, workOrderNo, bomCfg.PartNo);
                    int nRet = DataManager.DBHelper.Update(sql);
                }
            }

            return msg;
        }
        #endregion

        protected virtual XmlDocument CreateResponseXML(string cmdType, string cmdName, bool bRet, string msg, string data)
        {
            /*最终XML格式为 
             <root>
                <xmlprop cmdtype="client" cmdname="client" result="1"  message="ok"/>             
                <data><![CDATA[xxxx]]></data>
             </root> 
             */

            XmlDocument xmlDoc = new XmlDocument();

            //加入XML的声明段落
            XmlNode xmlnode = xmlDoc.CreateNode(XmlNodeType.XmlDeclaration, "", "");
            xmlDoc.AppendChild(xmlnode);

            //加入一个根元素
            XmlElement rootElem = xmlDoc.CreateElement("", "root", "");
            xmlDoc.AppendChild(rootElem);

            //加入xmlprop元素，本元素用来放一些 XML 属性
            XmlElement propElem = xmlDoc.CreateElement("xmlprop");
            rootElem.AppendChild(propElem);
            propElem.SetAttribute("cmdtype", cmdType);
            propElem.SetAttribute("cmdname", cmdName);
            propElem.SetAttribute("result", bRet ? "1" : "0");
            propElem.SetAttribute("message", msg);

            // 加入返回结果数据data元素，本元素用来放返回的Json数据等
            if (!string.IsNullOrEmpty(data))
            {
                XmlElement dataElem = xmlDoc.CreateElement("data");
                XmlCDataSection cdata = xmlDoc.CreateCDataSection(data);
                dataElem.AppendChild(cdata);
                rootElem.AppendChild(dataElem);
            }

            return xmlDoc;
        }
    }
}
